#ifndef	_TSPARCV9INTERNAL_H_
#define	_TSPARCV9INTERNAL_H_

#pragma ident	"@(#)tsparcv9internal.h	1.38	06/04/24 SMI"

#ifdef	__cplusplus
extern "C" {
#endif

		/*
		 * defines to support the values we stuff into the simcpu_t
		 * misc registers
		 */

#define	v9_ccr	miscreg[0]
#define	v9_asi	miscreg[1]
#define	v9_y	miscreg[2]
#define	v9_fsr_exc	miscreg[3]
#define	v9_fsr_tem	miscreg[4]
#define	v9_fsr_ctrl	miscreg[5]
#define	v9_gsr		miscreg[6]

#define	V9_FSR_RD_BIT		30
#define	V9_FSR_RD_MASK		MASK64(31,30)
#define	V9_FSR_TEM_BIT		23
#define	V9_FSR_TEM_MASK		MASK64(27,23)
#define	V9_FSR_NS_MASK		MASK64(22,22)
#define	V9_FSR_FTT_SHIFT	14
#define	V9_FSR_FTT_MASK		MASK64(16,14)
#define	V9_FSR_FCC0_SHIFT	10
#define	V9_FSR_FCC1_SHIFT	32
#define	V9_FSR_FCC_BITS		2
#define	V9_FSR_FCC_MASK		MASK64((V9_FSR_FCC_BITS - 1),0)
#define	V9_FSR_AEXC_MASK	MASK64(9,5)
#define	V9_FSR_CEXC_MASK	MASK64(4,0)

#define	V9_FSR_ALL_FCC_MASK	\
	(MASK64((V9_FSR_FCC1_SHIFT+(V9_FSR_FCC_BITS*3)-1),V9_FSR_FCC1_SHIFT) | \
	MASK64((V9_FSR_FCC0_SHIFT+V9_FSR_FCC_BITS-1),V9_FSR_FCC0_SHIFT))

/* ldfsr/ldxfsr mask - does not change reserved/readonly or ftt fields. */
#define	V9_FSR_REG_MASK		(V9_FSR_ALL_FCC_MASK | V9_FSR_RD_MASK | \
				V9_FSR_TEM_MASK | \
				V9_FSR_AEXC_MASK | V9_FSR_CEXC_MASK)

#define	V9_FSR_FCC0(_fsr)	(((_fsr) >> V9_FSR_FCC0_SHIFT) & V9_FSR_FCC_MASK)
/* _fccn can be 1, 2 or 3 */
#define	V9_FSR_FCCN(_fsr, _fccn)	(((_fsr) >> (V9_FSR_FCC1_SHIFT + (((_fccn) - 1) * V9_FSR_FCC_BITS))) & V9_FSR_FCC_MASK)

/* Bits in CEXC, AEXC and TEM */
#define	V9_FSR_NV_BIT		0x10
#define	V9_FSR_OF_BIT		0x08
#define	V9_FSR_UF_BIT		0x04
#define	V9_FSR_DZ_BIT		0x02
#define	V9_FSR_NX_BIT		0x01

/* GSR - General Status Register */
#define	V9_GSR_MASK_MASK	MASK64(63, 32)
#define	V9_GSR_IM_MASK		MASK64(27, 27)
#define	V9_GSR_IRND_SHIFT	25
#define	V9_GSR_IRND_MASK	MASK64(26, 25)
#define	V9_GSR_SCALE_MASK	MASK64(7, 3)
#define	V9_GSR_ALIGN_MASK	MASK64(2, 0)

#define	V9_GSR_REG_MASK	(V9_GSR_MASK_MASK | V9_GSR_IM_MASK | \
				V9_GSR_IRND_MASK | V9_GSR_SCALE_MASK | \
				V9_GSR_ALIGN_MASK)

#if OLDPIC	/* { */
	/*
	 * defines used for manipulating pcr and pic regs for niagara
	 *
	 *      PIC1        PIC0
	 *  [63------32][31------0]
	 */
/* Return the appropriate pic value from within the 64bit counter */
#define CPU_COUNTER_TO_PIC0(cntr)   ((cntr) & 0xFFFFFFFFULL)
#define CPU_COUNTER_TO_PIC1(cntr)   ((cntr) >> 32)

/* Update the 64bit counter with the appropriate pic value */
#define PIC0_TO_CPU_COUNTER(cntr, pic0)     ((cntr) | (pic0))
#define PIC1_TO_CPU_COUNTER(cntr, pic1)     ((cntr) | (((uint64_t)pic1) << 32))
#endif	/* } */


typedef enum {
	V9_UnInitialised,	/* Not a legit state - tells us allocated but not inited */
	V9_User, V9_Priv, V9_HyperPriv, V9_RED, V9_Error,
	V9_State_Max		/* Not a legit state - used to let us know the max number of states */
} sparcv9_state_t;

	/* For useful debugging stuff: */
extern char * sparcv9_state_name[];
 
typedef enum {
			/* 0x0	Reserved */
	Sparcv9_trap_power_on_reset			= 0x1,
	Sparcv9_trap_watchdog_reset			= 0x2,
	Sparcv9_trap_externally_initiated_reset		= 0x3,
	Sparcv9_trap_software_initiated_reset		= 0x4,
	Sparcv9_trap_RED_state_exception		= 0x5,
			/* 0x6-0x7	Reserved */
	Sparcv9_trap_instruction_access_exception	= 0x8,
	Sparcv9_trap_instruction_access_MMU_miss	= 0x9,
	Sparcv9_trap_instruction_access_error		= 0xa,
			/* 0xb-0xf	Reserved */
	Sparcv9_trap_illegal_instruction		= 0x10,
	Sparcv9_trap_privileged_opcode			= 0x11,
	Sparcv9_trap_unimplemented_LDD			= 0x12,
	Sparcv9_trap_unimplemented_STD			= 0x13,
			/* 0x14-0x1f	Reserved */
	Sparcv9_trap_fp_disabled			= 0x20,
	Sparcv9_trap_fp_exception_ieee_754		= 0x21,
	Sparcv9_trap_fp_exception_other			= 0x22,
	Sparcv9_trap_tag_overflow			= 0x23,
	Sparcv9_trap_clean_window			= 0x24,
			/* 0x25-0x27 clean_window reserved */
	Sparcv9_trap_division_by_zero			= 0x28,
	Sparcv9_trap_internal_processor_error		= 0x29,
			/* 0x2a-0x2f	Reserved */
	Sparcv9_trap_data_access_exception		= 0x30,
	Sparcv9_trap_data_access_MMU_miss		= 0x31,
	Sparcv9_trap_data_access_error			= 0x32,
	Sparcv9_trap_data_access_protection		= 0x33,
	Sparcv9_trap_mem_address_not_aligned		= 0x34,
	Sparcv9_trap_LDDF_mem_address_not_aligned	= 0x35,
	Sparcv9_trap_STDF_mem_address_not_aligned	= 0x36,
	Sparcv9_trap_privileged_action			= 0x37,
	Sparcv9_trap_LDQF_mem_address_not_aligned	= 0x38,
	Sparcv9_trap_STQF_mem_address_not_aligned	= 0x39,
			/* 0x3a-0x3f	Reserved */
	Sparcv9_trap_async_data_error			= 0x40,
	Sparcv9_trap_interrupt_level_1			= 0x41,
	Sparcv9_trap_interrupt_level_2			= 0x42,
	Sparcv9_trap_interrupt_level_3			= 0x43,
	Sparcv9_trap_interrupt_level_4			= 0x44,
	Sparcv9_trap_interrupt_level_5			= 0x45,
	Sparcv9_trap_interrupt_level_6			= 0x46,
	Sparcv9_trap_interrupt_level_7			= 0x47,
	Sparcv9_trap_interrupt_level_8			= 0x48,
	Sparcv9_trap_interrupt_level_9			= 0x49,
	Sparcv9_trap_interrupt_level_a			= 0x4a,
	Sparcv9_trap_interrupt_level_b			= 0x4b,
	Sparcv9_trap_interrupt_level_c			= 0x4c,
	Sparcv9_trap_interrupt_level_d			= 0x4d,
	Sparcv9_trap_interrupt_level_e			= 0x4e,
	Sparcv9_trap_interrupt_level_f			= 0x4f,
			/* 0x50-0x5f	Reserved */
			/* 0x60-0x7f	Impl Dep */

	Sparcv9_trap_spill_0_normal			= 0x80,
	Sparcv9_trap_spill_1_normal			= 0x84,
	Sparcv9_trap_spill_2_normal			= 0x88,
	Sparcv9_trap_spill_3_normal			= 0x8c,
	Sparcv9_trap_spill_4_normal			= 0x90,
	Sparcv9_trap_spill_5_normal			= 0x94,
	Sparcv9_trap_spill_6_normal			= 0x98,
	Sparcv9_trap_spill_7_normal			= 0x9c,

	Sparcv9_trap_spill_0_other			= 0xa0,
	Sparcv9_trap_spill_1_other			= 0xa4,
	Sparcv9_trap_spill_2_other			= 0xa8,
	Sparcv9_trap_spill_3_other			= 0xac,
	Sparcv9_trap_spill_4_other			= 0xb0,
	Sparcv9_trap_spill_5_other			= 0xb4,
	Sparcv9_trap_spill_6_other			= 0xb8,
	Sparcv9_trap_spill_7_other			= 0xbc,

	Sparcv9_trap_fill_0_normal			= 0xc0,
	Sparcv9_trap_fill_1_normal			= 0xc4,
	Sparcv9_trap_fill_2_normal			= 0xc8,
	Sparcv9_trap_fill_3_normal			= 0xcc,
	Sparcv9_trap_fill_4_normal			= 0xd0,
	Sparcv9_trap_fill_5_normal			= 0xd4,
	Sparcv9_trap_fill_6_normal			= 0xd8,
	Sparcv9_trap_fill_7_normal			= 0xdc,

	Sparcv9_trap_fill_0_other			= 0xe0,
	Sparcv9_trap_fill_1_other			= 0xe4,
	Sparcv9_trap_fill_2_other			= 0xe8,
	Sparcv9_trap_fill_3_other			= 0xec,
	Sparcv9_trap_fill_4_other			= 0xf0,
	Sparcv9_trap_fill_5_other			= 0xf4,
	Sparcv9_trap_fill_6_other			= 0xf8,
	Sparcv9_trap_fill_7_other			= 0xfc,

			/* trap		0x100-0x17f, */
	Sparcv9_trap_trap_instruction			= 0x100,
			/* htrap	0x180-0x1ff, */
	Sparcv9_trap_htrap_instruction			= 0x180,
	Sparcv9_trap_illegal_value			= 0x200
} sparcv9_trap_type_t;


typedef enum {
	v9_mm_tso = 0x0,
	v9_mm_pso = 0x1,
	v9_mm_rmo = 0x2,
	v9_mm_illegal = 0x3
} v9_mm_t;


typedef enum {
	SPARCv9_FTT_None		= 0,
	SPARCv9_FTT_IEEE_754_exception	= 1,
	SPARCv9_FTT_unfinished_FPop	= 2,
	SPARCv9_FTT_unimplemented_FPop	= 3,
	SPARCv9_FTT_sequence_error	= 4,
	SPARCv9_FTT_hardware_error	= 5,
	SPARCv9_FTT_invalid_fp_register	= 6,
	SPARCv9_FTT_reserved		= 7
} v9_fsr_ftt_t;


enum V9_MACCESS {
	MA_V9_LdFSR	= MA_Non_Gen_Base,
	MA_V9_LdXFSR	= MA_V9_LdFSR + MA_Non_Gen_Skip,
	MA_V9_StFSR	= MA_V9_LdXFSR + MA_Non_Gen_Skip,
	MA_V9_StXFSR	= MA_V9_StFSR + MA_Non_Gen_Skip
};


typedef enum {
	USE_ASI_REG,
	NO_FLAG
} asi_flag_t;


	/*
	 * The actual definition of sparcv9_cpu_t:
	 * private to this module
	 */


typedef struct {
	uint64_t	offset;
	bool_t		non_priv_trap;
} tick_counter_t;

typedef struct {
	uint64_t	compare;
	uint64_t	target;
	bool_t		interrupt_enabled;
	tick_counter_t	*counter;
} tick_compare_t;

		/*
		 * Legion debug features used by all sparcv9 processors
		 * and parsed from config file.
		 */
struct PROC_DEBUG {
	uint64_t	exit_at;		/* if set in conf file, exit when
						   we reach this num of instns */
	uint64_t	perf_cycle_gap;		/* Override PERF_CYCLE_GAP */
};


struct SPARCV9_CPU {
		/* Window registers */
	int		cwp;
	int		cansave;
	int		canrestore;
	int		otherwin;
	int		cleanwin;
	int		wstate_other;
	int		wstate_normal;

	int		active_window;	/* window currently in intreg file */
	int		active_global;	/* globals currently in intreg file */
					/* -1 if intregs not active */

#define	V9_WSTATE_NORMAL_BITS	0
#define	V9_WSTATE_OTHER_BITS	3
#define	V9_WSTATE_MASK		0x7



#define V9_REG_GROUP	8	/* 8 registers */
#define	V9_IN_OFFSET	24
#define	V9_LOCAL_OFFSET	16
#define	V9_OUT_OFFSET	8
	int		nwins;
	int		nwins_mask;	/* set to nwins-1 */
	uint64_t *	winsp;

#define	V9_GLOBAL_GROUP	8
#define	V9_GLOBAL_OFFSET 0
	int		nglobals;
	uint64_t *	globalsp;
	int		gl;
#define	Q_MAXPGL	2		/* Max GL for cpu obeying Q spec */

#define	V9_PSTATE_IE_BIT	1
#define	V9_PSTATE_PRIV_BIT	2
#define	V9_PSTATE_AM_BIT	3
#define	V9_PSTATE_PEF_BIT	4
#define	V9_PSTATE_MM_BITS	6
#define	V9_PSTATE_MM_MASK	0x3
#define	V9_PSTATE_TLE_BIT	8
#define	V9_PSTATE_CLE_BIT	9
#define	V9_PSTATE_TCT_BIT	12
	struct {
		bool_t	priv;		/* PRIV */
		bool_t	int_enabled;	/* IE */
		bool_t	addr_mask;	/* AM */
		v9_mm_t	mm;		/* memory mode */
		bool_t	fpu_enabled;	/* PEF */
		bool_t	cle;		/* CLE */
		bool_t	tle;		/* TLE */
		bool_t	tct;		/* TCT */
	} pstate;

#define	V9_HPSTATE_TLZ_BIT	0
#define	V9_HPSTATE_HPRIV_BIT	2
#define	V9_HPSTATE_RED_BIT	5
#define	V9_HPSTATE_IBE_BIT	10
	struct {
		bool_t	hpriv;
		bool_t	tlz;		/* trap level zero */
		bool_t	red;		/* RED */
		bool_t	ibe;		/* instruction breakpoint enable */
	} hpstate;

		/* Trap support registers */
	int		tl;		/* trap level reg */
	int		maxtl;		/* max supported (SPARCv9_TLSPACE-1) */		
	int		pil;		/* processor interrupt level */

#define	Q_MAXPTL	2		/* Max TL for cpu obeying Q spec */

#define	SPARCv9_TLSPACE	8
	tvaddr_t	tpc[SPARCv9_TLSPACE];	/* tpc[0] = TPC1 etc. */
	tvaddr_t	tnpc[SPARCv9_TLSPACE];
	uint64_t	tstate[SPARCv9_TLSPACE];
	uint16_t	tt[SPARCv9_TLSPACE];	/* trap type */
#define	N_TPC(_v9p, _tl)	(_v9p)->tpc[ (_tl)-1 ]
#define	N_TNPC(_v9p, _tl)	(_v9p)->tnpc[ (_tl)-1 ]
#define	N_TSTATE(_v9p, _tl)	(_v9p)->tstate[ (_tl)-1 ]
#define	N_TT(_v9p, _tl)		(_v9p)->tt[ (_tl)-1 ]

#define	V9_TT_MASK	0x1ff

	uint64_t	htstate[SPARCv9_TLSPACE];
#define	N_HTSTATE(_v9p, _tl)	(_v9p)->htstate[ (_tl)-1 ]

#define	V9_TBA_MASK	((tvaddr_t)~((1LL<<15)-1))
	tvaddr_t	tba;		/* trap base address */
#define	V9_HTBA_MASK	((tvaddr_t)~((1LL<<14)-1))
	tvaddr_t	htba;		/* hypervisor trap base address */

		/* Other misc registers */
	simcpu_t *	simp;

	tick_counter_t	*tick;
	tick_counter_t	*stick;
	tick_counter_t	_tick;
	tick_counter_t	_stick;

	tick_compare_t	tick_cmpr;
	tick_compare_t	stick_cmpr;
	tick_compare_t	hstick_cmpr;

	uint32_t	softint;

	sparcv9_state_t	state;
	uint64_t	ver;

PERFDEF(struct {
		simcycle_t	enter_icount;
		simcycle_t	icount[V9_State_Max];
	} perf; )

		/*
		 * Floating point state
		 * (NOTE: for efficiency, many fsr fields are implemented using
		 * simcpu_t private registers)
		 */

	bool_t		has_fpu;	/* true if this v9 cpu is supposed to have an fpu */
	bool_t		fpu_on;		/* true if is fully enabled (has_fpu, pstate.pef=1, fprs.fef=1) */
	struct {
		bool_t	fef;	/* floating point enabled in FPRS register */
				/* combine with pstate.pef to enable FPU */
		bool_t	du;
		bool_t	dl;
	} fprs;
#define	V9_FPRS_FEF_BIT	2
#define	V9_FPRS_DU_BIT	1
#define	V9_FPRS_DL_BIT	0

		/*
		 * Specific callbacks for the type of sparc core we have
		 */

	void (*read_state_reg)(simcpu_t* sp, int rdest, int state_regnum);
	void (*write_state_reg)(simcpu_t* sp, int state_regnum, uint64_t val);
	void (*read_priv_reg)(simcpu_t* sp, int rdest, int priv_regnum);
	void (*write_priv_reg)(simcpu_t* sp, int priv_regnum, uint64_t val);
	void (*read_hyp_priv_reg)(simcpu_t* sp, int rdest, int hpriv_regnum);
	void (*write_hyp_priv_reg)(simcpu_t* sp, int hpriv_regnum, uint64_t val);

	void (*done_retry)(simcpu_t* sp, bool_t is_done);
	void (*asi_access)(simcpu_t * sp, maccess_t op, int regnum, int asi, uint64_t reg1, uint64_t reg2, asi_flag_t asi_flag );

	void (*post_precise_trap)(simcpu_t * sp, sparcv9_trap_type_t v9trap);

		/* Pointer to implementation specific v9 info - for use with callbacks */
	void *	impl_specificp;

};




#define	NEXT_INSTN(_sp)	do { (_sp)->pc = (_sp)->npc; (_sp)->npc += 4; } while (0)
#define	SET_PC_WITH_DS(_sp, _targ)	do { (_sp)->pc = (_sp)->npc; (_sp)->npc = (_targ); } while (0)



extern void sparcv9_save_instr(simcpu_t * sp, int rdest_num, tvaddr_t newval);
extern void sparcv9_restore_instr(simcpu_t * sp, int rdest_num, tvaddr_t newval);
extern void sparcv9_return_instr(simcpu_t * sp, tvaddr_t newval);

extern void sparcv9_udiv64(simcpu_t * sp, int rdest_num, uint64_t a, uint64_t b);

	/*
	 * Other misc values
	 */


typedef enum {
	cond_a   = 0x8,
	cond_n   = 0x0,
	cond_ne  = 0x9,
	cond_e   = 0x1,
	cond_g   = 0xA,
	cond_le  = 0x2,
	cond_ge  = 0xB,
	cond_l   = 0x3,
	cond_gu  = 0xC,
	cond_leu = 0x4,
	cond_cc  = 0xD,
	cond_cs  = 0x5,
	cond_pos = 0xE,
	cond_neg = 0x6,
	cond_vc  = 0xF,
	cond_vs  = 0x7
} cond_type_t;

extern void sparcv9_trapcc(simcpu_t * sp, uint64_t tnum, int cc, cond_type_t cond);


/* iflush routines */

extern void ss_iflush_by_va(simcpu_t * sp, tvaddr_t va, int asi, int gran);	
extern void ss_iflush_by_pa(simcpu_t * sp, uint64_t pa, int gran);

/* FLUSH instruction granularity = 64 bytes */
#define SS_FLUSH_GRAN 	0x40

typedef enum {
	cc_bit_c = 0x1,
	cc_bit_v = 0x2,
	cc_bit_z = 0x4,
	cc_bit_n = 0x8
} cc_bit_t;

	/* macros to help with the formation of cc values */

#define	_V9_cc_n(_n)	((_n)<<3)
#define	_V9_cc_z(_z)	((_z)<<2)
#define	_V9_cc_v(_v)	((_v)<<1)
#define	_V9_cc_c(_c)	(_c)

#define	_V9_cc(_n, _z, _v, _c)	_V9_cc_n(_n)|_V9_cc_z(_z)|_V9_cc_v(_v)|_V9_cc_c(_c)
#define	V9_icc(_n, _z, _v, _c) _V9_cc(_n, _z, _v, _c)
#define	V9_xcc(_n, _z, _v, _c) (_V9_cc(_n, _z, _v, _c)<<4)

#define	V9_icc_n(_n)	((_n)<<3)
#define	V9_icc_z(_z)	((_z)<<2)
#define	V9_icc_v(_v)	((_v)<<1)
#define	V9_icc_c(_c)	(_c)

#define	V9_xcc_n(_n)	((_n)<<7)
#define	V9_xcc_z(_z)	((_z)<<6)
#define	V9_xcc_v(_v)	((_v)<<5)
#define	V9_xcc_c(_c)	((_c)<<4)


#define	V9_icc_n_mask	V9_icc_n(1ULL)
#define	V9_icc_z_mask	V9_icc_z(1ULL)
#define	V9_icc_v_mask	V9_icc_v(1ULL)
#define	V9_icc_c_mask	V9_icc_c(1ULL)
#define	V9_xcc_n_mask	V9_xcc_n(1ULL)
#define	V9_xcc_z_mask	V9_xcc_z(1ULL)
#define	V9_xcc_v_mask	V9_xcc_v(1ULL)
#define	V9_xcc_c_mask	V9_xcc_c(1ULL)

#define	V9_icc_mask	0x0f
#define	V9_xcc_mask	0xf0

#define	V9_ext_icc(_x)	((_x)&V9_icc_mask)
#define	V9_ext_xcc(_x)	(((_x)&V9_xcc_mask)>>4)

/* FPU condition codes */

#define	V9_fcc_u	3
#define	V9_fcc_g	2
#define	V9_fcc_l	1
#define	V9_fcc_e	0


uint64_t sparcv9_invert_endianess(uint64_t *regp, uint32_t count);

	/*
	 * Support functions for debugging Legion's SPARC v9 modules
	 */
#if !defined(NDEBUG)	/* { */

extern void sparcv9_dump_intregs(simcpu_t *sp);
extern void sparcv9_dump_state(simcpu_t *sp);

#endif	/* } */

#ifndef NDEBUG /* { */
#define	DBG_FSR	0x1000000000LL
#define	DBGFSR(s)	do { if (debug_bits & DBG_FSR) { s } } while (0)	/* floating point status register */
#define	DBG_FPRS	0x2000000000LL
#define	DBGFPRS(s)	do { if (debug_bits & DBG_FPRS) { s } } while (0)	/* floating point registers state */
#else 		/* } { */
#define	DBGFSR(s)	do { } while (0)
#define	DBGFPRS(s)	do { } while (0)
#endif /* } */

#ifndef FP_DECODE_DISABLED
#define	FP_EXEC_FPU_ON_CHECK \
	sparcv9_cpu_t * v9p = (sparcv9_cpu_t*)(sp->specificp); \
	if (!v9p->fpu_on) { \
		v9p->post_precise_trap(sp, Sparcv9_trap_fp_disabled); \
		return; \
	}
#else /* FP_DECODE_DISABLED */
#define	FP_EXEC_FPU_ON_CHECK
#endif /* FP_DECODE_DISABLED */

#ifdef	__cplusplus
}
#endif

#endif /* _TSPARCV9INTERNAL_H_ */
